package com.ice.work.moment.socket.listener;

import com.corundumstudio.socketio.SocketIOClient;
import com.corundumstudio.socketio.annotation.OnConnect;
import com.corundumstudio.socketio.annotation.OnDisconnect;
import com.corundumstudio.socketio.annotation.OnEvent;
import com.honeybee.cloud.framework.base.exception.business.BaseBizException;
import com.honeybee.cloud.framework.common.idwork.IdWorker;
import com.honeybee.cloud.framework.common.response.ResponseEntity;
import com.honeybee.cloud.framework.validation.utils.ValidatorUtils;
import com.ice.work.moment.facade.socket.dto.PushAuthorizationDTO;
import com.ice.work.moment.facade.socket.dto.PushUserDTO;
import com.ice.work.moment.facade.socket.mapper.ParamConvertMapper;
import com.ice.work.moment.facade.socket.model.PushUser;
import com.ice.work.moment.facade.socket.params.LoginParam;
import com.ice.work.moment.facade.socket.request.AckRequest;
import com.ice.work.moment.facade.socket.request.LoginRequest;
import com.ice.work.moment.facade.socket.request.LogoutRequest;
import com.ice.work.moment.facade.socket.request.SendMessageRequest;
import com.ice.work.moment.facade.socket.store.GlobalStore;
import com.ice.work.moment.socket.service.IPushAuthorizationService;
import com.ice.work.moment.socket.service.IPushUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.validation.ConstraintViolationException;
import java.util.Objects;

/**
 * @Description 推送监听
 * @Author DELL
 * @Create 2019-04-17
 * @Since 1.0.0
 */
@Component
@Slf4j
@SuppressWarnings("all")
public class PushEventListener {

    @Autowired
    private IPushAuthorizationService pushAuthorizationService;
    @Autowired
    private IPushUserService pushUserService;
    @Autowired
    private IdWorker idWorker;


    @OnConnect
    public void onConnect(SocketIOClient client) {
        log.info("web客户端建立连接:{}", client.getRemoteAddress());
        log.info("web客户端建立连接sessionId:{}", client.getSessionId());
    }

    /**
     * 登录
     *
     * @param client
     * @param request
     */
    @OnEvent("login")
    public void login(SocketIOClient client, LoginRequest request) {
        ResponseEntity result;
        try {
            log.info("登录信息:{}", request);
            log.info("登录sessionId:{}", client.getSessionId());
            //已经登录过了，只是重连
            if (Objects.nonNull(request.getPushId())) {
                PushUserDTO pushUserDTO = pushUserService.findByPushId(request.getPushId());
                if (Objects.nonNull(pushUserDTO)) {
                    result = ResponseEntity.ok(pushUserDTO.getId());
                    client.sendEvent("loginSuccess", result);
                    return;
                }
            }

            //未登录过的
            ValidatorUtils.validate(request);
            //鉴权
            LoginParam loginParam = ParamConvertMapper.INSTANCE.toParam(request);
            PushAuthorizationDTO pushAuthorizationDTO = pushAuthorizationService.login(loginParam);
            //获取pushId并保存
            PushUser pushUser = PushUser.builder().id(idWorker.nextId()).pushAuthorizationId(pushAuthorizationDTO.getId()).build();
            Boolean isSuccess = pushUserService.add(pushUser);
            GlobalStore.WEB_SOCKET_CLIENT.put(pushUser.getId(), client);
            GlobalStore.SESSION_CLIENT.put(client.getSessionId(), pushUser.getId());
            if (isSuccess) {
                result = ResponseEntity.ok(pushUser.getId());
                client.sendEvent("loginSuccess", result);
            } else {
                result = ResponseEntity.error("登录失败");
                client.sendEvent("loginFail", result);
            }
        } catch (ConstraintViolationException e) {
            log.error("登录ConstraintViolationException", e);
            result = ResponseEntity.error(e);
            client.sendEvent("loginFail", result);
        } catch (BaseBizException e) {
            log.error("登录BusinessException", e);
            result = ResponseEntity.error(e);
            client.sendEvent("loginFail", result);
        } catch (Exception e) {
            log.error("登录Exception", e);
            result = ResponseEntity.error("登录失败");
            client.sendEvent("loginFail", result);
        }

    }

    /**
     * 登出
     *
     * @param client
     * @param request
     */
    @OnEvent("logout")
    public void logout(SocketIOClient client, LogoutRequest request) {
        ResponseEntity result;
        try {
            log.info("登出信息:{}", request);
            log.info("登出sessionId:{}", client.getSessionId());
            ValidatorUtils.validate(request);
            pushUserService.logout(request.getPushId());
            result = ResponseEntity.ok(request.getPushId());
            client.sendEvent("logoutSuccess", result);
            GlobalStore.WEB_SOCKET_CLIENT.remove(request.getPushId());
            GlobalStore.SESSION_CLIENT.remove(client.getSessionId());
        } catch (ConstraintViolationException e) {
            log.error("登出ConstraintViolationException", e);
            result = ResponseEntity.error(e);
            client.sendEvent("loginFail", result);
        } catch (BaseBizException e) {
            log.error("登出BusinessException", e);
            result = ResponseEntity.error(e);
            client.sendEvent("loginFail", result);
        } catch (Exception e) {
            log.error("登出Exception", e);
            result = ResponseEntity.error("登出失败");
            client.sendEvent("loginFail", result);
        }
    }

    /**
     * 发送消息到特定的pushId
     *
     * @param client
     * @param request
     */
    @OnEvent("sendMessage")
    public void sendMessage(SocketIOClient client, SendMessageRequest request) {
        ResponseEntity result;
        try {
            log.info("接收信息:{}", request);
            ValidatorUtils.validate(request);
            SocketIOClient sendClient = GlobalStore.WEB_SOCKET_CLIENT.get(request.getPushId());
            if (Objects.isNull(sendClient)) {
                result = ResponseEntity.error("接收方不在线");
                client.sendEvent("sendFail", result);
                return;
            }
            result = ResponseEntity.ok(request.getMessage());
            try {
                client.sendEvent("sendMessage", result);
            } catch (Exception e) {
                log.error("推送消息异常", e);
            }
            client.sendEvent("sendSuccess", result);
        } catch (ConstraintViolationException e) {
            log.error("接收ConstraintViolationException", e);
            result = ResponseEntity.error(e);
            client.sendEvent("sendFail", result);
        } catch (BaseBizException e) {
            log.error("接收BusinessException", e);
            result = ResponseEntity.error(e);
            client.sendEvent("sendFail", result);
        } catch (Exception e) {
            log.error("接收Exception", e);
            result = ResponseEntity.error("发送失败");
            client.sendEvent("sendFail", result);
        }
    }

    /**
     * 确认收到消息信息
     *
     * @param client
     * @param request
     */
    @OnEvent("ack")
    public void accpt(SocketIOClient client, AckRequest request) {
        log.info("接收到的响应信息:{}", request);
        ResponseEntity result;
        try {
            ValidatorUtils.validate(request);
            GlobalStore.CHECK_RESPONSE.add(request);
        } catch (Exception e) {
            log.error("接收Exception", e);
            result = ResponseEntity.error("发送失败");
            client.sendEvent("sendFail", result);
        }
    }

    @OnDisconnect
    public void onDisconnect(SocketIOClient client) {
        log.info("web客户端断开连接sessionId:{}", client.getSessionId());
        Long pushId = GlobalStore.SESSION_CLIENT.get(client.getSessionId());
        if (Objects.isNull(pushId)) {
            return;
        }
        log.info("web客户端断开连接pushId:{}", pushId);
        LogoutRequest request = new LogoutRequest();
        request.setPushId(pushId);
        logout(client, request);
    }
}
